package repository

import (
	"context"
	"database/sql"
	"gitee.com/zhangyu520cw/basic-go/webook/internal/domain"
	"gitee.com/zhangyu520cw/basic-go/webook/internal/repository/cache"
	"gitee.com/zhangyu520cw/basic-go/webook/internal/repository/dao"
	"github.com/gin-gonic/gin"
	"log"
)

var (
	ErrRecordNotFound = dao.ErrRecordNotFound
	ErrDuplicateEmail = dao.ErrDuplicateEmail
)

func NewRepository(dao *dao.UserDao, cache cache.UserCache) *UserRepository {
	return &UserRepository{
		dao:   dao,
		cache: cache,
	}
}

type UserRepository struct {
	dao   *dao.UserDao
	cache cache.UserCache
}

func (repo *UserRepository) Create(ctx context.Context, u domain.User) error {
	return repo.dao.Insert(ctx, dao.User{
		Email: sql.NullString{
			String: u.Email,
			Valid:  u.Email != "",
		},
		Password: u.Password,
	})

}

func (repo *UserRepository) FindByEmail(ctx context.Context, email string) (domain.User, error) {
	u, err := repo.dao.FindByEmail(ctx, email)
	if err != nil {
		return domain.User{}, err
	}
	user, err := repo.toDomain(u)
	return user, err
}

func (repo *UserRepository) toDomain(u dao.User) (domain.User, error) {
	return domain.User{
		Id:       u.Id,
		Email:    u.Email.String,
		Password: u.Password,
	}, nil
}

func (repo *UserRepository) UpdateNonZeroFields(ctx *gin.Context, user domain.User) error {
	return repo.dao.UpdateById(ctx, repo.toEntity(user))
}

func (repo *UserRepository) toEntity(user domain.User) dao.User {
	return dao.User{
		Id: user.Id,
		Email: sql.NullString{
			String: user.Email,
			Valid:  user.Email != "",
		},
		Password: user.Password,
		Birthday: user.Birthday.UnixMilli(),
		AboutMe:  user.AboutMe,
		Nickname: user.Nickname,
	}
}

func (repo *UserRepository) FindById(ctx *gin.Context, uid int64) (domain.User, error) {
	du, err := repo.cache.Get(ctx, uid)
	// 主要err为Nil，就返回
	if err == nil {
		return du, nil
	}
	// err 不为nil，就要查询数据库
	// err 有两种可能
	// 1.key 不存在，说明redis是正常的
	// 2. 访问redis有问题，可能是网络有问题，也可能是redis有问题
	u, err := repo.dao.FindById(ctx, uid)
	if err != nil {
		return domain.User{}, err
	}
	du, err = repo.toDomain(u)
	if err != nil {
		return domain.User{}, err
	}
	go func() {
		err = repo.cache.Set(ctx, du)
		// 网络崩溃，也可能是redis崩溃
		if err != nil {
			log.Println(err)
		}
	}()
	//_ = repo.cache.Set(ctx, du)
	return du, nil
}
